//Defintion of Trait:  
//  A trait is a collection of methods defined for an unknown type: Self. 
//  They can access other methods declared in the same trait.

trait Animal {
    fn new(name: &'static str) -> Self;

    fn name(&self) -> &'static str;
    fn noise(&self) -> &'static str;

    fn talk(&self) {
        println!("{} says {}", self.name(), self.noise());
    }
}


struct Sheep {
    naked: bool, 
    name: &'static str
}

impl Sheep {
    fn is_naked(&self) -> bool {
        self.naked
    }
    fn shear(&mut self) {
        if self.is_naked() {
            //NOTE: no member function of self.name() , but you can impl other trait for Self and then
            // call it success
            println!("{} is already naked...", self.name());
        }
        else{
            println!("{} gets a haircut!", self.name);
            self.naked = true;
        }
    }
}

impl Animal for Sheep {
    fn new(name: &'static str) -> Sheep {
        Sheep {name: name, naked: false}
    }

    fn name(&self) -> &'static str {
        self.name
    }
    fn noise(&self) -> &'static str {
        if self.is_naked() {
            "baaaaah?"
        }
        else {
            "baaaaah!"
        }
    }
    fn talk(&self){
        println!("{} pauses briefly... {}", self.name, self.noise());
    }
}

pub fn main(){
    let mut sheep = Sheep{naked: true,  name: "dolly"};
    sheep.shear();

    //Type annotation is necessary in this case.
    let mut dolly: Sheep = Animal::new("Dolly");   
    // Remove type annotation will compile failed!
    
    //NOTE: interface.static_function will override by type's impl


    dolly.talk();
    dolly.shear();
    dolly.talk();

}
